package dantzig_wolfe_decomposition;

import gurobi.GRB;
import gurobi.GRBEnv;
import gurobi.GRBException;
import gurobi.GRBLinExpr;
import gurobi.GRBModel;
import gurobi.GRBVar;

import Jama.Matrix;

public class MainProblem {

    private GRBEnv env;
    private GRBModel model;
    private int variableSetNum;
    private int[] xNum;
    private GRBVar[][] x;

    public Matrix[] solutions; // 决策变量的值，列向量
    public Matrix shadowPrice; // 对偶变量的值，行向量

    MainProblem(Matrix[] extremePoints) {
        variableSetNum = extremePoints.length;
        xNum = new int[variableSetNum];
        for (int i = 0; i < variableSetNum; i++) {
            xNum[i] = extremePoints[i].getColumnDimension();
        }

        try {
            env = new GRBEnv(true);
            env.start();
            model = new GRBModel(env);
            model.set("OutputFlag", "0");

            // 创建决策变量
            x = new GRBVar[variableSetNum][];
            for (int i = 0; i < variableSetNum; i++) {
                x[i] = model.addVars(xNum[i], GRB.CONTINUOUS);
            }

            // 设置目标函数
            GRBLinExpr expr = new GRBLinExpr();
            for (int i = 0; i < variableSetNum; i++) {
                Matrix temp = new Matrix(Dataset.benefit[i], 1);
                expr.addTerms(temp.times(extremePoints[i]).getArray()[0], x[i]);
            }
            model.setObjective(expr, GRB.MAXIMIZE);

            // 添加公共资源约束
            expr = new GRBLinExpr();
            for (int i = 0; i < variableSetNum; i++) {
                Matrix temp = new Matrix(Dataset.iron[i], 1);
                expr.addTerms(temp.times(extremePoints[i]).getArray()[0], x[i]);
            }
            model.addConstr(expr, GRB.LESS_EQUAL, Dataset.constraint[variableSetNum][0], "iron");

            // 添加极点比例约束
            for (int i = 0; i < variableSetNum; i++) {
                expr = new GRBLinExpr();
                expr.addTerms(new Matrix(1, xNum[i], 1).getArray()[0], x[i]);
                model.addConstr(expr, GRB.EQUAL, 1, "c" + i);
            }
        } catch (GRBException e) {
            System.out.println("Error code: " + e.getErrorCode() + ". " + e.getMessage());
        }
    }

    public void solve() {

        try {

            // 求解模型
            model.optimize();

            // 读取决策变量的值
            solutions = new Matrix[variableSetNum];

            for (int i = 0; i < variableSetNum; i++) {
                solutions[i] = new Matrix(xNum[i], 1, 0);
                for (int j = 0; j < x[i].length; j++) {
                    solutions[i].set(j, 0, x[i][j].get(GRB.DoubleAttr.X));
                }
            }

            // 获取对偶变量的值
            shadowPrice = new Matrix(model.get(GRB.DoubleAttr.Pi, model.getConstrs()), 1);

            model.dispose();
            env.dispose();

        } catch (GRBException e) {
            System.out.println("Error code: " + e.getErrorCode() + ". " + e.getMessage());
        }

    }

}
